/*
 *    Copyright (c) 2018-2025, haohanwork.com All rights reserved.
 */
package com.haohan.cloud.scm.goods.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.haohan.cloud.scm.api.common.tree.TreeUtil;
import com.haohan.cloud.scm.api.constant.ScmCacheNameConstant;
import com.haohan.cloud.scm.api.constant.enums.opc.YesNoEnum;
import com.haohan.cloud.scm.api.goods.dto.GoodsCategoryTree;
import com.haohan.cloud.scm.api.goods.entity.CategoryRelation;
import com.haohan.cloud.scm.api.goods.entity.GoodsCategory;
import com.haohan.cloud.scm.goods.mapper.GoodsCategoryMapper;
import com.haohan.cloud.scm.goods.service.CategoryRelationService;
import com.haohan.cloud.scm.goods.service.GoodsCategoryService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 商品分类
 *
 * @author haohan
 * @date 2019-05-13 18:46:41
 */
@Service
@AllArgsConstructor
public class GoodsCategoryServiceImpl extends ServiceImpl<GoodsCategoryMapper, GoodsCategory> implements GoodsCategoryService {

    private final CategoryRelationService categoryRelationService;

    @Override
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean save(GoodsCategory entity) {
        return retBool(baseMapper.insert(entity));
    }

    @Override
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean updateById(GoodsCategory entity) {
        return retBool(baseMapper.updateById(entity));
    }

    @Override
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean removeById(Serializable id) {
        return SqlHelper.delBool(baseMapper.deleteById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean saveCategory(GoodsCategory category) {
        // 一级节点设置默认父级
        parentHandle(category);
        baseMapper.insert(category);
        categoryRelationService.insertCategoryRelation(category.getId(), category.getParentId(), GoodsCategory.class);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean updateCategoryById(GoodsCategory category) {
        GoodsCategory exist = baseMapper.selectById(category.getId());
        // 修改父级(parentId 为空时不修改父级)
        if (null != category.getParentId() && !StrUtil.equals(exist.getParentId(), category.getParentId())) {
            parentHandle(category);
            //更新区域层级关系
            CategoryRelation relation = new CategoryRelation();
            relation.setAncestor(category.getParentId());
            relation.setDescendant(category.getId());
            relation.setClassName(GoodsCategory.class.getSimpleName());
            categoryRelationService.updateCategoryRelation(relation);
        }
        return retBool(baseMapper.updateById(category));
    }

    private void parentHandle(GoodsCategory category) {
        // 一级节点设置默认父级
        String parentId = category.getParentId();
        GoodsCategory parent = StrUtil.isBlank(parentId) || StrUtil.equals(TreeUtil.ROOT, parentId) ? null : baseMapper.selectById(parentId);
        if (null == parent) {
            category.setParentId(TreeUtil.ROOT);
            // 兼容原系统
            category.setParentIds(TreeUtil.ROOT + StrUtil.COMMA);
        } else {
            category.setParentIds(parent.getParentIds() + parentId + StrUtil.COMMA);
        }
    }

    /**
     * 删除分类及子分类
     *
     * @param categoryId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, condition = "#result", allEntries = true)
    public boolean removeCategoryById(String categoryId) {
        Set<String> ids = fetchChildren(categoryId);
        //删除区域级联关系
        categoryRelationService.deleteAllCategoryRelation(ids, GoodsCategory.class);
        // 同时删除子区域
        return SqlHelper.delBool(baseMapper.deleteBatchIds(ids));
    }

    /**
     * 根据分类名称 查找分类, 只返回一个
     *
     * @param shopId       可为null
     * @param categoryName
     * @return
     */
    @Override
    public GoodsCategory fetchByName(String shopId, String categoryName) {
        return baseMapper.selectList(Wrappers.<GoodsCategory>query().lambda()
                .eq(StrUtil.isNotBlank(shopId), GoodsCategory::getShopId, shopId)
                .eq(GoodsCategory::getName, categoryName)
        ).stream().findFirst().orElse(null);
    }

    /**
     * 查询子分类id
     *
     * @param goodsCategoryId
     * @return 当前分类id加入结果集
     */
    @Override
    public Set<String> fetchChildren(String goodsCategoryId) {
        GoodsCategory category = baseMapper.selectById(goodsCategoryId);
        Set<String> childSet;
        if (null == category) {
            childSet = new HashSet<>(4);
        } else {
            childSet = categoryRelationService.fetchAllDescendant(goodsCategoryId, GoodsCategory.class.getSimpleName());
        }
        childSet.add(goodsCategoryId);
        return childSet;
    }

    /**
     * 获取分类的所有父级
     *
     * @param goodsCategoryId
     * @return
     */
    @Override
    public List<GoodsCategory> fetchParentList(String goodsCategoryId) {
        return fetchParent(goodsCategoryId, false);
    }

    /**
     * 查询分类及所有父级
     *
     * @param categoryId
     * @return
     */
    @Override
    public List<GoodsCategory> fetchAllParentWithSelf(String categoryId) {
        return fetchParent(categoryId, true);
    }

    private List<GoodsCategory> fetchParent(String categoryId, boolean withSelf) {
        Set<String> parentIdSet = categoryRelationService.fetchAllAncestor(categoryId, GoodsCategory.class.getSimpleName());
        if (withSelf) {
            parentIdSet.add(categoryId);
        }
        if (parentIdSet.isEmpty()) {
            return new ArrayList<>();
        }
        return baseMapper.selectList(Wrappers.<GoodsCategory>query().lambda()
                .in(GoodsCategory::getId, parentIdSet)
        );
    }


    /**
     * 分类树
     *
     * @param shopId
     * @param allShow
     * @return
     */
    @Override
    @Cacheable(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, key = "#shopId + #allShow")
    public List<GoodsCategoryTree> selectTree(String shopId, boolean allShow) {
        // 分类只要 需展示的
        List<GoodsCategoryTree> treeList = fetchCategoryTree(baseMapper.selectList(Wrappers.<GoodsCategory>query().lambda()
                .eq(!allShow, GoodsCategory::getCategoryType, YesNoEnum.yes)
                .eq(GoodsCategory::getShopId, shopId)));
        return TreeUtil.build(treeList, TreeUtil.ROOT);
    }

    /**
     * 分类列表转为 分类树节点列表
     *
     * @param list
     * @return
     */
    private List<GoodsCategoryTree> fetchCategoryTree(List<GoodsCategory> list) {
        return list.stream()
                // 正常数据父id不为自己
                .filter(category -> !category.getId().equals(category.getParentId()))
                // 节点排序 升序
                .sorted((c1, c2) -> {
                    if (null == c1.getSort()) {
                        return 1;
                    } else if (null == c2.getSort()) {
                        return -1;
                    } else {
                        return c1.getSort().compareTo(c2.getSort());
                    }
                })
                .map(category -> {
                    GoodsCategoryTree node = new GoodsCategoryTree();
                    node.setId(category.getId());
                    node.setParentId(category.getParentId());
                    node.setName(category.getName());
                    node.setShopId(category.getShopId());
                    node.setSort(category.getSort());
                    node.setLogo(category.getLogo());
                    node.setCategoryType(category.getCategoryType());
                    node.setStatus(category.getStatus());
                    return node;
                }).collect(Collectors.toList());
    }

    /**
     * 当前租户下所有分类层级关系更新
     *
     * @return
     */
    @Override
    @CacheEvict(value = ScmCacheNameConstant.GOODS_CATEGORY_TREE, allEntries = true)
    public Boolean updateAllRelation() {
        try {
            categoryRelationService.updateAllRelation(fetchCategoryTree(this.list(Wrappers.emptyWrapper())), GoodsCategory.class);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

}
